eletrotupi / tcc/ frontend/app/medicine-regimens/[id].tsxc901c35af9c84b6a29e5185545ced1129f33b8f4
7.0 KB | 233 lines Raw
1
import {
2
  View,
3
  StyleSheet,
4
  KeyboardAvoidingView,
5
  ScrollView,
6
  TouchableOpacity,
7
  ActivityIndicator,
8
} from "react-native";
9
import { Text } from "@/components/ui/Text";
10
import { useState } from "react";
11
import { router, useLocalSearchParams } from "expo-router";
12
import { Card } from "@/components/ui/Cards";
13
import { Input } from "@/components/ui/Input";
14
import { Button } from "@/components/ui/Button";
15
import { Section, SectionHeader } from "@/components/ui/Sections";
16
import { Spacing, Typography, Colors, BorderRadius } from "@/constants/theme";
17
import { TimePicker } from "@/components/ui/TimePicker";
18
import { useMedicineRegimen, useUpdateMedicineRegimen } from "@/hooks";
19
import type { MedicinePeriodicity, MedicineRegimen } from "@/lib/api";
20

21
const PERIODICITY_OPTIONS: { label: string; value: MedicinePeriodicity }[] = [
22
  { label: "Uma vez", value: "ONCE" },
23
  { label: "Diário", value: "DAILY" },
24
  { label: "2x ao dia", value: "TWICE_DAILY" },
25
  { label: "3x ao dia", value: "THREE_TIMES_DAILY" },
26
  { label: "Semanal", value: "WEEKLY" },
27
  { label: "Quinzenal", value: "BIWEEKLY" },
28
  { label: "Mensal", value: "MONTHLY" },
29
];
30

31
function getTimePickerCount(p: MedicinePeriodicity): number {
32
  switch (p) {
33
    case "ONCE": return 0;
34
    case "DAILY": return 1;
35
    case "TWICE_DAILY": return 2;
36
    case "THREE_TIMES_DAILY": return 3;
37
    default: return 1;
38
  }
39
}
40

41
function timesToDates(times: string[]): Date[] {
42
  return times.map((t) => {
43
    const [h, m] = t.split(":").map(Number);
44
    const d = new Date();
45
    d.setHours(h, m, 0, 0);
46
    return d;
47
  });
48
}
49

50
export default function MedicineRegimenEdit() {
51
  const { id } = useLocalSearchParams<{ id: string }>();
52
  const { data, isLoading } = useMedicineRegimen(id);
53

54
  if (isLoading) {
55
    return (
56
      <View style={styles.center}>
57
        <ActivityIndicator color={Colors.light.tint} />
58
      </View>
59
    );
60
  }
61

62
  if (!data?.regimen) {
63
    return null;
64
  }
65

66
  return <MedicineRegimenForm id={id} regimen={data.regimen} />;
67
}
68

69
function MedicineRegimenForm({ id, regimen }: { id: string; regimen: MedicineRegimen }) {
70
  const updateRegimen = useUpdateMedicineRegimen();
71

72
  const [name, setName] = useState(regimen.name);
73
  const [dosage, setDosage] = useState(regimen.dosage);
74
  const [periodicity, setPeriodicity] = useState<MedicinePeriodicity>(regimen.periodicity);
75
  const [scheduledTimes, setScheduledTimes] = useState<Date[]>(
76
    timesToDates(regimen.scheduledAt),
77
  );
78

79
  const handleSave = async () => {
80
    const count = getTimePickerCount(periodicity);
81
    const scheduledAt = scheduledTimes.slice(0, count).map(
82
      (d) =>
83
        `${d.getHours().toString().padStart(2, "0")}:${d.getMinutes().toString().padStart(2, "0")}`
84
    );
85

86
    await updateRegimen.mutateAsync({
87
      id,
88
      payload: { name, dosage, periodicity, scheduledAt },
89
    });
90
    router.back();
91
  };
92

93
  return (
94
    <KeyboardAvoidingView behavior="height" style={styles.keyboardView}>
95
      <ScrollView scrollEventThrottle={16}>
96
        <View style={styles.container}>
97
          <View style={styles.header}>
98
            <Text style={styles.headerTitle}>Editar medicamento</Text>
99
            <Text style={styles.headerSubtitle}>
100
              Atualize os detalhes do medicamento
101
            </Text>
102
          </View>
103

104
          <Section>
105
            <SectionHeader title="Detalhes" />
106
            <Card style={{ padding: Spacing.cardGap }}>
107
              <Input
108
                label="Nome"
109
                value={name}
110
                onChangeText={setName}
111
                placeholder="Ex: Fluoxetina"
112
                variant="darkGhost"
113
              />
114
              <Input
115
                label="Dosagem"
116
                value={dosage}
117
                onChangeText={setDosage}
118
                placeholder="Ex: 20mg"
119
                variant="darkGhost"
120
              />
121
            </Card>
122
          </Section>
123

124
          <Section>
125
            <SectionHeader title="Frequência" />
126
            <View style={styles.periodicityRow}>
127
              {PERIODICITY_OPTIONS.map((opt) => (
128
                <TouchableOpacity
129
                  key={opt.value}
130
                  style={[
131
                    styles.periodicityChip,
132
                    periodicity === opt.value && styles.periodicityChipActive,
133
                  ]}
134
                  onPress={() => {
135
                    setPeriodicity(opt.value);
136
                    const count = getTimePickerCount(opt.value);
137
                    setScheduledTimes((prev) =>
138
                      count === 0
139
                        ? []
140
                        : count > prev.length
141
                        ? [...prev, ...Array(count - prev.length).fill(new Date())]
142
                        : prev.slice(0, count)
143
                    );
144
                  }}
145
                  activeOpacity={0.7}
146
                >
147
                  <Text
148
                    style={[
149
                      styles.periodicityChipLabel,
150
                      periodicity === opt.value && styles.periodicityChipLabelActive,
151
                    ]}
152
                  >
153
                    {opt.label}
154
                  </Text>
155
                </TouchableOpacity>
156
              ))}
157
            </View>
158
          </Section>
159

160
          {scheduledTimes.length > 0 && (
161
            <Section>
162
              <SectionHeader
163
                title={scheduledTimes.length === 1 ? "Horário" : "Horários"}
164
              />
165
              {scheduledTimes.map((t, i) => (
166
                <View style={{ marginTop: 10 }} key={i}>
167
                  <TimePicker
168
                    value={t}
169
                    onChange={(date) =>
170
                      setScheduledTimes((prev) =>
171
                        prev.map((v, idx) => (idx === i ? date : v))
172
                      )
173
                    }
174
                  />
175
                </View>
176
              ))}
177
            </Section>
178
          )}
179

180
          <Button
181
            title="Salvar"
182
            onPress={handleSave}
183
            loading={updateRegimen.isPending}
184
            disabled={!name || !dosage}
185
          />
186
        </View>
187
      </ScrollView>
188
    </KeyboardAvoidingView>
189
  );
190
}
191

192
const styles = StyleSheet.create({
193
  keyboardView: { flex: 1 },
194
  center: { flex: 1, alignItems: "center", justifyContent: "center" },
195
  container: {
196
    gap: 24,
197
    paddingHorizontal: Spacing.containerPadding,
198
    paddingVertical: Spacing.sectionGap,
199
    marginBottom: 50,
200
  },
201
  header: { gap: 8 },
202
  headerTitle: { ...Typography.headlineMd },
203
  headerSubtitle: {
204
    ...Typography.bodyMd,
205
    color: Colors.light.textSecondary,
206
  },
207
  periodicityRow: {
208
    flexDirection: "row",
209
    flexWrap: "wrap",
210
    gap: 8,
211
  },
212
  periodicityChip: {
213
    paddingHorizontal: 16,
214
    paddingVertical: 10,
215
    borderRadius: BorderRadius.full,
216
    backgroundColor: "#fff",
217
    borderWidth: 1.5,
218
    borderColor: Colors.light.divider,
219
  },
220
  periodicityChipActive: {
221
    backgroundColor: Colors.light.tint + "1A",
222
    borderColor: Colors.light.tint,
223
  },
224
  periodicityChipLabel: {
225
    fontSize: 14,
226
    fontWeight: "500",
227
    color: Colors.light.text,
228
  },
229
  periodicityChipLabelActive: {
230
    fontWeight: "600",
231
    color: Colors.light.text,
232
  },
233
});